package tt.dz.egobus.servicemanager.base.dialect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.SerializationException;
import org.hibernate.usertype.UserType;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;

/**
 * @author Anson
 * @date 17-8-25
 * @name 基于jsonb实现的hibernate的类
 * @since 1.0.6
 */
public class ServiceManagerJsonbType implements UserType {

    //转换器
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Override
    public void nullSafeSet(PreparedStatement ps, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            ps.setNull(index, Types.OTHER);
            return;
        }
        try {
            String dbValue = MAPPER.writeValueAsString(value);
            ps.setObject(index, dbValue, Types.OTHER);
        } catch (Exception ex) {
            throw new HibernateException(ex);
        }
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        final String cellContent = rs.getString(names[0]);
        if (cellContent == null) {
            return null;
        }
        try {
            return JSON.parse(cellContent);
        } catch (Exception ex) {
            throw new HibernateException(ex);
        }
    }

    @Override
    public Object deepCopy(Object originalValue) throws HibernateException {
        try {
            byte[] bytes = MAPPER.writeValueAsBytes(originalValue);
            return JSON.parse(bytes);
        } catch (IOException ex) {
            throw new HibernateException(ex);
        }
    }


    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        Object deepCopy = deepCopy(value);
        if (!Serializable.class.isAssignableFrom(deepCopy.getClass())) {
            throw new SerializationException(
                    String.format("deepCopy of %s is not serializable", value), null);
        }
        return (Serializable) deepCopy;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return deepCopy(cached);
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return deepCopy(original);
    }

    @Override
    public boolean isMutable() {
        return true;
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return Objects.requireNonNull(x).hashCode();
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return ObjectUtils.nullSafeEquals(x, y);
    }

    @Override
    public Class<?> returnedClass() {
        return JSONObject.class;
    }

    @Override
    public int[] sqlTypes() {
        return new int[]{Types.JAVA_OBJECT};
    }
}
